package bieche.eric.beans;

import bieche.eric.util.TribblePlayer;
import bieche.eric.util.TribbleRound;
import java.util.*;
import java.io.Serializable;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.application.*;
import javax.faces.validator.ValidatorException;
import com.icesoft.faces.component.ext.HtmlInputText;

/**
 * <ul type='disc'>
 *   <li>If necessary, enter the current round.</li> 
 *   <li>When a player or players score the same type and same number of points check their names.</li>
 *   <li>Click on the button that represents the type of points scored.</li>
 *   <li>Click on th  button that represents the type of points scored.</li>
 *   <li>Enter the number of each tribble type scored.</li>
 *   <li>All players selected will score those points for that round.</li>
 *   <li>When you hover over a player's score for a particular round the details are displayed</li>
 * </ul>
 * 
 * <ol type='1'>
 *    <li><b>Quadruple</b> - If you win the round with this tribble in your play pile, this tribble is worth 40,000 instead of 10,000.  (This tribble cannot be copied.)</li> 
 *    <li><b>Go</b> - Take another turn (that is, play the next tribble number in sequence).</li>
 *    <li><b>Safety</b> - If this tribble is in your play pile at the end of the round, you may shuffle your hand into your draw deck instead of placing your hand in your discard pile.</li>
 *    <li><b>Process</b> - Draw three cards, then choose two cards from hand to place beneath your draw deck.</li>
 *    <li><b>Freeze</b> - Name a tribble power.  Until the end of your next turn this round, players cannot play tribbles with that power (whether the power is used or not)</li>
 *    <li><b>Battle</b> - Choose another player to reveal the top three cards of his or her draw deck.  You reveal the top three cards of your draw deck.  Each player with the highest total places those cards under his or her play pile; the other player discards his or her cards.</li>
 *    <li><b>Toxin</b> - Each other player reveals the top card of his or her draw deck for each Discard tribble in his or her play pile.  Choose one revealed card and score points equal to the number of tribbles on that card.  Each player who revealed cards places those cards in his or her hand.</li>
 *    <li><b>Evolve</b> - Count the number of cards in your hand, place your hand in your discard pile, and draw that many cards.</li>
 *    <li><b>Mutate</b> - Count the number of cards in your play pile.  Shuffle your play pile into your draw deck, then put that many cards from the top of your draw deck in your play pile.</li>
 *    <li><b>Tally</b> - If another player is about to score points from this tribble, he or she scores half this tribble's value instead, and you score an equal number of points.</li>
 *    <li><b>Discard</b> - Choose one card in your hand to place in your discard pile.</li>
 *    <li><b>Poison</b> - Choose any opponent who still has card(s) in their draw deck.  That opponent must discard the top card, and you immediately score points equal to the number of tribbles on that card.</li>
 *    <li><b>Rescue</b> - Look through your discard pile and recover a card.  Place it face-down on top of your draw deck - or, if it has the proper number of tribbles, you may play it now.</li>
 *    <li><b>Clone</b> - This tribble may be played even when it has the same number of tribbles as the last card played.</li>
 *    <li><b>Cycle</b> - Place a tribble in hand beneath your draw deck to draw a card.</li>
 *    <li><b>Exchange</b> - Discard a tribble from hand to take a tribble into hand from your discard pile.</li>
 *    <li><b>Replay</b> - Search your play pile for a tribble and play it again.</li>
 *    <li><b>Copy</b> - You may immediately use the game text of the top tribble of any other play pile.</li>
 *    <li><b>Draw</b> - Choose a player.  He or she must draw a card.</li>
 *    <li><b>Score</b> - Choose a player.  If that player plays a tribble on his or her next turn, you score points equal to the number of tribbles on that card.</li>
 *    <li><b>Kill</b> - Choose a player to discard the top tribble of his or her play pile.</li>
 *    <li><b>Recycle</b> - Choose a player to shuffle his or her discard pile into his or her draw deck.</li>
 *    <li><b>Antidote</b> - If this tribble is poisoned, its owner scores points instead and may place his or her hand beneath his or her draw deck.</li>
 *    <li><b>Skip</b> - Skip the next player.</li>
 *    <li><b>Reverse</b> - Reverse the direction of play from clockwise to counterclockwise (or vice versa).</li>
 *    <li><b>Famine</b> - The next tribble in sequence is 1.</li>
 *    <li><b>Avalanche</b> - If you have least four other cards in hand, all players discard a card.  You may then discard one extra.</li>
 *    <li><b>Stampede</b> - All players may immediately play the next tribble in sequence.  only the tribble you play may activate its power.</li>
 *    <li><b>Time Warp</b> - If this tribble is in your play pile at the end of the round and you did not go out, start with one less card in your hand the next round (not cumulative with other 10,000 Time Warp tribbles in your play pile).
 *    <li><b>Recycle&Reverse</b> - Choose a player to shuffle his or her discard pile into his or her draw deck, then reverse the direction of play from clockwise to counterclockwise (or vice versa).</li>
 *    <li><b>Clone&Reverse</b> - Reverse the direction of play from clockwise to counterclockwise (or vice versa).  This tribble may be played even when it has the same number of tribbles as the last card played.</li>
 *    <li><b>Clone&Skip</b> - Skip the next player.  This tribble may be played even when it has the same number of tribbles as the last card played.</li>
 *    <li><b>Bonus&Freeze</b> - Name a tribble power.  Until the end of your next turn this round, players cannot play tribbles with that power (whether the power is used or not)</li>
 * </ol>
 * @author biecheer
 */
public class FormBean implements Serializable
{
   
   /**
    * Auto-Generated eclipse id.
    */
   private static final long serialVersionUID = 166870335348202422L;

   private String name;
   private List<TribblePlayer> players;
   private int currentRound = 1;
   private int scoreType = -1;

   public int getCurrentRound() { return this.currentRound; }
   public void setCurrentRound(int round)
   { 
      this.currentRound = round;
   }

   public int getScoreType() { return this.scoreType; }

   private boolean addNamesPopupRendered = true;
   public boolean isAddNamesPopupRendered() { return addNamesPopupRendered; }
   public void setAddNamesPopupRendered(boolean tf) { this.addNamesPopupRendered = tf; }
   public void toggleAddNamesPopup(ActionEvent event) { this.addNamesPopupRendered = ! this.addNamesPopupRendered; }

   private boolean scorePaddPopupRendered = false;
   public boolean getScorePaddPopupRendered() { return this.scorePaddPopupRendered; }
   public boolean isScorePaddPopupRendered() { return this.scorePaddPopupRendered; }
   public void setScorePaddPopupRendered(boolean tf) { this.scorePaddPopupRendered = tf; }
   public void toggleScorePaddPopup(ActionEvent event) { this.scorePaddPopupRendered = ! this.scorePaddPopupRendered; }
   public void closeScorePaddPopup(ActionEvent event)
   {
      this.clearScore();
      for(TribblePlayer tp : this.players) { tp.setSelected( false ); }
      this.toggleScorePaddPopup( null );
   }

   private boolean errorMessagePopupRendered = false;
   public boolean isErrorMessagePopupRendered() { return errorMessagePopupRendered; }
   public void setErrorMessagePopupRendered(boolean errorMessagePopupRendered) { this.errorMessagePopupRendered = errorMessagePopupRendered; }
   public void toggleErrorMessagePopup(ActionEvent event)
   {
      errorMessagePopupRendered =  ! errorMessagePopupRendered;
   }

   public String errorMessagePopup = "";
   public String getErrorMessagePopup() { return errorMessagePopup; }
   public void setErrorMessagePopup(String errorMessagePopup) { this.errorMessagePopup = errorMessagePopup; }

   public List< TribblePlayer > getPlayers() { return players; }
   public String getName() { return name; }
   public void setName( String name ) { this.name = name; }

   public FormBean()
   {
      this.players = new ArrayList<TribblePlayer>();
      this.clearScore();
   }

   public void addPlayer(ActionEvent ae)
   {
      if( this.name != null && ! this.name.isEmpty() )
      {
         getPlayers().add( new TribblePlayer(this.name) );
         this.name = "";
      }
      // When the user presses the Add Player button set the focus back on the inputText for name.
      this.nameText.requestFocus();
   }

   private HtmlInputText nameText = null;
   public HtmlInputText getNameText() { return nameText; }
   public void setNameText(HtmlInputText nameText) { this.nameText = nameText; }   

   /**
    * Used to check the list of player names to make sure that the person wasn't added before.
    *
    * @param context
    * @param component
    * @param value
    * @throws ValidatorException
    */
   public void validatePlayerNameBeforeAdd(FacesContext context, UIComponent component, Object value) throws ValidatorException
   {
      String checkName = (String) value;

      for(TribblePlayer tp : getPlayers())
      {
         if(tp.getName().equals( checkName ))
         {
            String msg = "Error: Trying to add Player:" + checkName + " whom already exists.  You can append a number if you'd like..." + checkName + "1";
            FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);

            throw new ValidatorException(fm);
         }
      }
   }


/////////////////////////////////
   
   private int hundredThousands;
   private int tenThousands;
   private int thousands;
   private int hundreds;
   private int tens;
   private int ones;

   public void clearScore()
   {
      this.hundredThousands = 0; this.tenThousands = 0;
      this.thousands = 0; this.hundreds = 0; this.tens = 0;
      this.ones = 0;
   }

   public void clearScore(ActionEvent event)
   {
      this.clearScore();
   }

   /**
    * BONUS score is an automatic 100k for each play who has attained it for the Round.
    */
   public void scoreBonus()
   {
      for(TribblePlayer tp : this.players)
      {
         if(tp.isSelected() && tp.getRounds().get( this.currentRound - 1 ).getBonusPoints() == 0)
         {
            tp.scorePoints( this.scoreType, 100000, this.currentRound );
         }
         tp.setSelected( false );   // It's okay to set everyone's selected flag to false....
      }
   }

   public void advanceRound(ActionEvent event) { if(this.currentRound < 5) this.currentRound++; }

   /**
    * 
    * @param event
    */
   public void scorePoints(ActionEvent event)
   {
      int score = (hundredThousands * 100000) + (tenThousands * 10000) + (thousands * 1000) +
                  (hundreds * 100) + (tens * 10) + ones;

      if(this.scoreType == TribbleRound.TALLY) { score /= 2; }

      for(TribblePlayer tp : this.players)
      {
         if(tp.isSelected())
         {
            tp.scorePoints( this.scoreType, score, this.currentRound );
         }
      }

      this.closeScorePaddPopup( null );
   }

   public boolean anySelectedPlayers()
   {
      for(TribblePlayer tp : this.players)
      {
         if(tp.isSelected()) return true;
      }
      this.setErrorMessagePopup( "Error: you need to select at least one player to score points.");
      this.setErrorMessagePopupRendered( true );
      return false;
   }

   public void scorePoison(ActionEvent ae)    { this.scoreType = TribbleRound.POISON;    if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreToxin(ActionEvent ae)     { this.scoreType = TribbleRound.TOXIN;     if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreWinner(ActionEvent ae)    { this.scoreType = TribbleRound.WINNER;    if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreCopy(ActionEvent ae)      { this.scoreType = TribbleRound.COPY;      if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreAntidote(ActionEvent ae)  { this.scoreType = TribbleRound.ANTIDOTE;  if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreQuadruple(ActionEvent ae) { this.scoreType = TribbleRound.QUADRUPLE; if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreScore(ActionEvent ae)     { this.scoreType = TribbleRound.SCORE;     if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }
   public void scoreBonus(ActionEvent ae)     { this.scoreType = TribbleRound.BONUS;     if(anySelectedPlayers()) this.scoreBonus(); }
   public void scoreTally(ActionEvent ae)     { this.scoreType = TribbleRound.TALLY;     if(anySelectedPlayers()) this.setScorePaddPopupRendered( true ); }

   public int getHundredThousands() { return hundredThousands; }
   public void setHundredThousands( int hundredThousands ) { this.hundredThousands = hundredThousands; }

   public int getTenThousands() { return tenThousands; }
   public void setTenThousands( int tenThousands ) { this.tenThousands = tenThousands; }

   public int getThousands() { return thousands; }
   public void setThousands( int thousands ) { this.thousands = thousands; }

   public int getHundreds() { return hundreds; }
   public void setHundreds( int hundreds ) { this.hundreds = hundreds; }

   public int getTens() { return tens; }
   public void setTens( int tens ) { this.tens = tens; }

   public int getOnes() { return ones; }
   public void setOnes( int ones ) { this.ones = ones; }

}//End of Class
